package cate.game.role.farm.adventure;


import cate.common.annotation.SplitParse;
import cate.common.table.d.GDAdventure;
import cate.common.table.d.GDFunc;
import cate.common.table.farm.adventure.row.AdventureCharpterRow;
import cate.common.table.farm.adventure.row.DropConditionRow;
import cate.common.util.SplitParser;
import cp.solution.util.str.Str;
import cate.game.res.MixRes;
import cate.game.res.drop.DropConfigHelper;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteField;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AdventureRandomDrop extends RoleDependent {

    @NoteField(value = "上一次生成挂机掉落的时间")
    public Map<Integer, Long> lastBuildRandomRewardTimeMap;

    @NoteField(value = "上一次领取挂机掉落的时间")
    public Map<Integer, Long> lastGotRandomRewardTimeMap;

    @NoteField(value = "未结算分钟数")
    public Map<Integer, Long> remainMinutesMap;

    @NoteField(value = "掉落组list")
    public List<AdventureRandomDrop.DropItem> list = new ArrayList<>();

    @NoteField(value = "掉落组2list")
    public List<AdventureRandomDrop.DropItem2> conditionDrops;

    public void initialize(Role role) {
        super.initialize(role);
        if (lastBuildRandomRewardTimeMap == null) {
            lastBuildRandomRewardTimeMap = new HashMap<>();
        }
        if (lastGotRandomRewardTimeMap == null) {
            lastGotRandomRewardTimeMap = new HashMap<>();
        }
        if (conditionDrops == null) {
            conditionDrops = new ArrayList<>();
        }
        if (remainMinutesMap == null) {
            remainMinutesMap = new HashMap<>();
        }
        updateDropGroup();
    }

    public void parse(String config) {
        if (StringUtils.isBlank(config)) {
            return;
        }
        list = SplitParser.parse(AdventureRandomDrop.DropItem.class, config);
        list.removeIf(a -> a.weight <= 0);
    }

    public List<DropItem2> parse2(List<String> strList) {
        List<DropItem2> drops = new ArrayList<>();
        for (String str : strList) {
            if (StringUtils.isBlank(str)) {
                continue;
            }
            List<String> strs = Str.strArr2strList(str.split("&"));
            DropItem2 drop = new DropItem2();
            String[] s = strs.get(0).split(":");
            if (s.length < 2) {
                drop.interval = 1;
                drop.dropId = Integer.parseInt(s[0]);
            } else {
                drop.interval = Integer.parseInt(s[0]);
                drop.dropId = Integer.parseInt(s[1]);
            }
            drop.conditions = Str.strArr2intList(strs.get(1).split(":"));
            drops.add(drop);
        }
        return drops;
    }

    public static class DropItem {
        @SplitParse(defaultValue = "1", note = "挂机随机掉落时间间隔")
        public int interval;
        @SplitParse(order = 1, defaultValue = "10003", note = "挂机掉落分组")
        public int dropId;
        @SplitParse(order = 2, defaultValue = "100", note = "掉落概率，100则百分百掉落")
        public double weight;
    }

    public static class DropItem2 {
        @NoteField(value = "时间间隔")
        public int interval;
        @NoteField(value = "掉落组id")
        public int dropId;
        @NoteField(value = "掉落id")
        public List<Integer> conditions;
    }

    public void updateDropGroup() {
        AdventureCharpterRow row = role.getFarm().adventure.getRow();
        if (row != null) {
            parse(row.dropIdHangCode);
            if (row.drop2StrList != null && row.drop2StrList.size() > 0) {
                conditionDrops = parse2(row.drop2StrList);
            }
            for (DropItem item : list) {
                updateMap(item.dropId);
            }
            for (DropItem2 item : conditionDrops) {
                updateMap(item.dropId);
            }
        }
    }

    private void updateMap(int dropId) {
        long lastHangGotTime = role.getFarm().adventure.lastHangGotTime;
        if (!lastGotRandomRewardTimeMap.containsKey(dropId)) {
            lastGotRandomRewardTimeMap.put(dropId, lastHangGotTime);
        }
        if (!lastBuildRandomRewardTimeMap.containsKey(dropId)) {
            lastBuildRandomRewardTimeMap.put(dropId, lastHangGotTime);
        }
        if (!remainMinutesMap.containsKey(dropId)) {
            remainMinutesMap.put(dropId, 0L);
        }
    }

    @JsonIgnore
    public MixRes getHangRandomDropReward(int funcId, boolean watch) {
        updateDropGroup();
        //最大挂机分钟数
        int max = role.getGame().table.vip.base.getByLevel(role.getBase().vip).hangMinites;
        long now = System.currentTimeMillis();
        MixRes reward = new MixRes();
        // 距离上次领取奖励经过的时间
        for (DropItem item : list) {
            int times = calAndSettleTimes(item.dropId, item.interval, max, now);
            // 根据挂机时间计算收益
            MixRes res = buildRewardHang(times, funcId, item, watch);
            reward.addList(res);
        }
        for (DropItem2 item :
                conditionDrops) {
            if (!judgeCondition(item.conditions)) {
                continue;
            }
            int times = calAndSettleTimes(item.dropId, item.interval, max, now);
            MixRes res = buildConditionRewardHang(times, funcId, item, watch);
            if (!res.isEmpty()) {
                reward.addList(res);
            }
            // 根据挂机时间计算收益

        }
        return reward;
    }

    public int calAndSettleTimes(int dropId, int interval, int max, long now) {
        long minutes = calHangMinutes(dropId, max, now) + remainMinutesMap.get(dropId);
        int times = (int) minutes / interval;
        remainMinutesMap.put(dropId, (minutes % interval));
        return times;
    }

    //计算随机掉落奖励结算次数
    private int calHangMinutes(int dropId, int max, long now) {
        long lastHangGotTime = lastGotRandomRewardTimeMap.get(dropId);
        long lastBuildRewardTime = lastBuildRandomRewardTimeMap.get(dropId);
        int getPastMinutes = (int) ((now - lastHangGotTime) / (60000));
        //超过最大挂机时间
        if (getPastMinutes > max) {
            getPastMinutes = max;
        }
        //已经结算过的时间
        int settleMiutes = (int) ((lastBuildRewardTime - lastHangGotTime) / (60000));
        if (settleMiutes < 0) {
            settleMiutes = 0;
        }
        //本次需要结算的分钟数
        return Math.max(getPastMinutes - settleMiutes, 0);
    }

    @JsonIgnore
    public MixRes getQuickFightReward(int minutes, int funcId) {
        MixRes reward = new MixRes();
        updateDropGroup();
        for (DropItem item : list) {
            int times = calQuickTimes(item.dropId, item.interval, minutes);
            MixRes res = buildRewardHang(times, funcId, item, false);
            reward.addList(res);
        }
        for (DropItem2 item :
                conditionDrops) {
            if (!judgeCondition(item.conditions)) {
                continue;
            }
            int times = calQuickTimes(item.dropId, item.interval, minutes);
            MixRes res = buildConditionRewardHang(times, funcId, item, false);
            if (!res.isEmpty()) {
                reward.addList(res);
            }
        }
        return reward;
    }

    private int calQuickTimes(int dropId, int interval, int minutes) {
        long remainMinutes = remainMinutesMap.get(dropId);
        int times = (int)(minutes + remainMinutes) / interval;
        remainMinutesMap.put(dropId, (minutes + remainMinutes) % interval);
        return times;
    }

    public MixRes buildRewardHang(int times, int funcId, DropItem item, boolean watch) {
        MixRes reward = new MixRes();
        for (int i = 0; i < times; i++) {
            if (item.weight >= (int) (100 * Math.random())) {
                reward.addList(buildReward(item.dropId));
            }
        }
        updateRewardTimeMap(times, funcId, item.dropId, item.interval, watch);
        return reward;
    }

    public MixRes buildConditionRewardHang(int times, int funcId, DropItem2 item, boolean watch) {
        MixRes reward = new MixRes();
        if (!judgeCondition(item.conditions)) {
            return reward;
        }
        for (int i = 0; i < times; i++) {
            reward.addList(buildReward(item.dropId));
        }
        updateRewardTimeMap(times, funcId, item.dropId, item.interval, watch);
        return reward;
    }

    public boolean judgeCondition(List<Integer> conditions) {
        boolean flag = false;
        for (int id :
                conditions) {
            DropConditionRow row = getConditionRow(id);
            if (row == null) {
                continue;
            }
            switch (row.type) {
                case GDAdventure.Type.OPEN_DAY:
                    flag = role.getGame().getOpenDay() >= row.condition;
                    break;
                case GDAdventure.Type.ROLE_LEVEL:
                    flag = role.getBase().level >= row.condition;
                    break;
                case GDAdventure.Type.VIP_LEVEL:
                    flag = role.getBase().vip >= row.condition;
                    break;
                default:
                    flag = false;
            }
            if (!flag) {
                return flag;
            }
        }
        return flag;
    }

    public DropConditionRow getConditionRow(int id) {
        return role.getGame().table.adventure.dropCondition.get(id);
    }

    private void updateRewardTimeMap(int times, int funcId, int dropId, int interval, boolean watch) {
        long now = System.currentTimeMillis();
        if (funcId == GDFunc.ADVENTURE_HANG) {
            if (!watch) {
                lastGotRandomRewardTimeMap.put(dropId, now);
            }
            lastBuildRandomRewardTimeMap.compute(dropId, (k, v) -> {
                if (lastBuildRandomRewardTimeMap.containsKey(dropId)) {
                    int max = role.getGame().table.vip.base.getByLevel(role.getBase().vip).hangMinites;
                    if (times < max / interval) {
                        v += times * interval * 60000;
                    } else {
                        v = now;
                    }
                    return v;
                }
                return role.getFarm().adventure.lastHangGotTime;
            });
        }
    }

    /**
     * 动态生成奖励
     */
    private MixRes buildReward(Integer dropId) {
        return DropConfigHelper.getDropReward(role.getGame(), dropId);
    }

    public void resetRewardTime() {
        lastGotRandomRewardTimeMap.values().forEach(item -> item = System.currentTimeMillis());
        lastBuildRandomRewardTimeMap.values().forEach(item -> item = System.currentTimeMillis());
        remainMinutesMap.values().forEach(item -> item = 0L);
    }
}
